package com.icongyou.enterprise.talent_marking.service.impl;

import com.icongyou.enterprise.data_aggregation.entity.*;
import com.icongyou.enterprise.data_aggregation.mapper.DataAggregationMapper;
import com.icongyou.enterprise.talent_marking.entity.PerformanceChanges;
import com.icongyou.enterprise.talent_marking.entity.StudentPerformanceSnapshots;
import com.icongyou.enterprise.talent_marking.mapper.PerformanceChangeMapper;
import com.icongyou.enterprise.talent_marking.mapper.StudentPerformanceTrackingServiceMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
@DisplayName("学生绩效跟踪服务测试")
class StudentPerformanceTrackingServiceImplTest {

    @Mock
    private PerformanceChangeMapper changesMapper;

    @Mock
    private StudentPerformanceTrackingServiceMapper trackingServiceMapper;

    @Mock
    private DataAggregationMapper dataAggregationMapper;
    
    @Mock
    private StudentPerformanceTrackingServiceMapper studentPerformanceTrackingServiceMapper;

    @InjectMocks
    private StudentPerformanceTrackingServiceImpl trackingService;

    private String studentId;
    private String courseId;
    private CourseProgressEntity courseProgress;
    private StudentPerformanceSnapshots lastSnapshot;

    @BeforeEach
    void setUp() {
        studentId = "STUDENT001";
        courseId = "COURSE001";

        // 初始化课程进度数据
        courseProgress = new CourseProgressEntity();
        courseProgress.setCourseId(courseId);
        courseProgress.setTotalScore(BigDecimal.valueOf(85.0));
        courseProgress.setRanking(10);
        courseProgress.setCompletedTasks(8);

        // 初始化上周快照
        lastSnapshot = new StudentPerformanceSnapshots();
        lastSnapshot.setStudentId(studentId);
        lastSnapshot.setCourseId(courseId);
        lastSnapshot.setCourseName("Java编程");
        lastSnapshot.setCourseTotalScore(BigDecimal.valueOf(80.0));
        lastSnapshot.setCourseRanking(15);
        lastSnapshot.setCompletedTasks(6);
        lastSnapshot.setRecentContributions("[]");
        lastSnapshot.setActiveAssignments("[]");
        lastSnapshot.setSnapshotDate(LocalDate.now().minusWeeks(1));
    }

    // ==================== simplifiedWeeklyTracking 测试 ====================

    @Test
    @DisplayName("每周跟踪任务 - 有跟踪学生")
    void testSimplifiedWeeklyTracking_WithTrackedStudents() {
        // Arrange
        List<String> studentIds = Arrays.asList("STUDENT001", "STUDENT002");
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(studentIds);

        List<CourseProgressEntity> courses = Arrays.asList(courseProgress);
        when(dataAggregationMapper.selectCourseProgressByStudentId(anyString())).thenReturn(courses);
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(anyString(), anyString(), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(trackingServiceMapper, times(2)).insert(any(StudentPerformanceSnapshots.class));
    }

    @Test
    @DisplayName("每周跟踪任务 - 无跟踪学生")
    void testSimplifiedWeeklyTracking_NoTrackedStudents() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Collections.emptyList());

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(dataAggregationMapper, never()).selectCourseProgressByStudentId(anyString());
        verify(trackingServiceMapper, never()).insert(any(StudentPerformanceSnapshots.class));
    }

    @Test
    @DisplayName("每周跟踪任务 - 学生无课程")
    void testSimplifiedWeeklyTracking_StudentHasNoCourses() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Collections.emptyList());

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(trackingServiceMapper, never()).insert(any(StudentPerformanceSnapshots.class));
    }

    @Test
    @DisplayName("每周跟踪任务 - 快照已存在跳过")
    void testSimplifiedWeeklyTracking_SnapshotAlreadyExists() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(eq(studentId), eq(courseId), any(LocalDate.class))).thenReturn(true);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(trackingServiceMapper, never()).insert(any(StudentPerformanceSnapshots.class));
    }

    @Test
    @DisplayName("每周跟踪任务 - 处理异常不中断")
    void testSimplifiedWeeklyTracking_ExceptionDoesNotStop() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList("STUDENT001", "STUDENT002"));
        when(dataAggregationMapper.selectCourseProgressByStudentId("STUDENT001"))
            .thenThrow(new RuntimeException("Database error"));
        when(dataAggregationMapper.selectCourseProgressByStudentId("STUDENT002"))
            .thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert - 第二个学生仍然被处理(generateSnapshot和detectChanges各调用一次)
        verify(dataAggregationMapper, times(2)).selectCourseProgressByStudentId("STUDENT002");
    }

    // ==================== 成绩变化检测测试 ====================

    @Test
    @DisplayName("检测成绩变化 - 成绩提升")
    void testDetectScoreChange_ScoreIncreased() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeastOnce()).insert(captor.capture());
        
        boolean hasScoreChange = captor.getAllValues().stream()
            .anyMatch(change -> "成绩变化".equals(change.getChangeType()));
        assertTrue(hasScoreChange, "应该检测到成绩变化");
    }

    @Test
    @DisplayName("检测成绩变化 - 成绩无变化")
    void testDetectScoreChange_NoChange() {
        // Arrange
        courseProgress.setTotalScore(BigDecimal.valueOf(80.0)); // 与lastSnapshot相同
        
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeast(0)).insert(captor.capture());
        
        boolean hasScoreChange = captor.getAllValues().stream()
            .anyMatch(change -> "成绩变化".equals(change.getChangeType()));
        assertFalse(hasScoreChange, "成绩未变化，不应该检测到变化");
    }

    @Test
    @DisplayName("检测成绩变化 - 成绩为null")
    void testDetectScoreChange_ScoreNull() {
        // Arrange
        courseProgress.setTotalScore(null);
        
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeast(0)).insert(captor.capture());
        
        boolean hasScoreChange = captor.getAllValues().stream()
            .anyMatch(change -> "成绩变化".equals(change.getChangeType()));
        assertFalse(hasScoreChange);
    }

    // ==================== 排名变化检测测试 ====================

    @Test
    @DisplayName("检测排名变化 - 排名上升")
    void testDetectRankingChange_RankingImproved() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeastOnce()).insert(captor.capture());
        
        boolean hasRankingChange = captor.getAllValues().stream()
            .anyMatch(change -> "排名变化".equals(change.getChangeType()));
        assertTrue(hasRankingChange);
    }

    @Test
    @DisplayName("检测排名变化 - 排名无变化")
    void testDetectRankingChange_NoChange() {
        // Arrange
        courseProgress.setRanking(15); // 与lastSnapshot相同
        
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeast(0)).insert(captor.capture());
        
        boolean hasRankingChange = captor.getAllValues().stream()
            .anyMatch(change -> "排名变化".equals(change.getChangeType()));
        assertFalse(hasRankingChange);
    }

    // ==================== 进度变化检测测试 ====================

    @Test
    @DisplayName("检测进度变化 - 完成任务增加")
    void testDetectProgressChange_TasksIncreased() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeastOnce()).insert(captor.capture());
        
        boolean hasProgressChange = captor.getAllValues().stream()
            .anyMatch(change -> "进度变化".equals(change.getChangeType()));
        assertTrue(hasProgressChange);
    }

    @Test
    @DisplayName("检测进度变化 - 完成任务为null")
    void testDetectProgressChange_CompletedTasksNull() {
        // Arrange
        courseProgress.setCompletedTasks(null);
        lastSnapshot.setCompletedTasks(null);
        
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeast(0)).insert(captor.capture());
        
        boolean hasProgressChange = captor.getAllValues().stream()
            .anyMatch(change -> "进度变化".equals(change.getChangeType()));
        assertFalse(hasProgressChange);
    }

    // ==================== 新任务检测测试 ====================

    @Test
    @DisplayName("检测新任务 - 有新任务")
    void testDetectNewAssignments_WithNewAssignments() {
        // Arrange
        AssignmentStudentEntity newAssignment = new AssignmentStudentEntity();
        newAssignment.setAssignmentId("ASSIGNMENT001");
        newAssignment.setStudentId(studentId);
        
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(eq(studentId), eq(courseId), any(LocalDateTime.class)))
            .thenReturn(Arrays.asList(newAssignment));
        when(dataAggregationMapper.selectAssignmentNameById("ASSIGNMENT001")).thenReturn("新作业");
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeastOnce()).insert(captor.capture());
        
        boolean hasNewAssignment = captor.getAllValues().stream()
            .anyMatch(change -> "新任务分配".equals(change.getChangeType()));
        assertTrue(hasNewAssignment);
    }

    @Test
    @DisplayName("检测新任务 - 无新任务")
    void testDetectNewAssignments_NoNewAssignments() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeast(0)).insert(captor.capture());
        
        boolean hasNewAssignment = captor.getAllValues().stream()
            .anyMatch(change -> "新任务分配".equals(change.getChangeType()));
        assertFalse(hasNewAssignment);
    }

    // ==================== 贡献度检测测试 ====================

    @Test
    @DisplayName("检测贡献度 - 有新提交贡献度")
    void testDetectContributions_WithNewSubmissions() {
        // Arrange
        SubmissionEntity submission = new SubmissionEntity();
        submission.setSubmissionId("SUB001");
        submission.setAssignmentId("ASSIGNMENT001");
        
        SubmissionEntity.ContributionItem item = new SubmissionEntity.ContributionItem();
        item.setStudentId(studentId);
        item.setRate(BigDecimal.valueOf(80.0));
        submission.setContributionRate(Arrays.asList(item));
        
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(eq(studentId), eq(courseId), any(LocalDateTime.class)))
            .thenReturn(Arrays.asList(submission));
        when(dataAggregationMapper.selectAssignmentNameById("ASSIGNMENT001")).thenReturn("团队作业");

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeastOnce()).insert(captor.capture());
        
        boolean hasContributionRecord = captor.getAllValues().stream()
            .anyMatch(change -> "贡献度记录".equals(change.getChangeType()));
        assertTrue(hasContributionRecord);
    }

    @Test
    @DisplayName("检测贡献度 - 贡献度为空")
    void testDetectContributions_EmptyContributionRate() {
        // Arrange
        SubmissionEntity submission = new SubmissionEntity();
        submission.setSubmissionId("SUB001");
        submission.setAssignmentId("ASSIGNMENT001");
        submission.setContributionRate(Collections.emptyList());
        
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(eq(studentId), eq(courseId), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(eq(studentId), eq(courseId), any(LocalDateTime.class)))
            .thenReturn(Arrays.asList(submission));

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeast(0)).insert(captor.capture());
        
        boolean hasContributionRecord = captor.getAllValues().stream()
            .anyMatch(change -> "贡献度记录".equals(change.getChangeType()));
        assertFalse(hasContributionRecord);
    }

    // ==================== 辅助方法测试 ====================

    @Test
    @DisplayName("获取课程名称 - 成功")
    void testGetCourseName_Success() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(dataAggregationMapper).selectCourseNameById(courseId);
    }

    @Test
    @DisplayName("获取课程名称 - 异常返回默认值")
    void testGetCourseName_Exception() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenThrow(new RuntimeException("DB error"));
        // 移除不必要的stubbing - 异常发生后这些方法不会被调用

        // Act & Assert - 不应该抛出异常
        assertDoesNotThrow(() -> trackingService.simplifiedWeeklyTracking());
    }

    @Test
    @DisplayName("获取任务名称 - 异常返回默认值")
    void testGetAssignmentName_Exception() {
        // Arrange
        AssignmentStudentEntity newAssignment = new AssignmentStudentEntity();
        newAssignment.setAssignmentId("ASSIGNMENT001");
        
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(anyString(), anyString(), any(LocalDate.class)))
            .thenReturn(lastSnapshot);
        when(dataAggregationMapper.selectNewAssignmentsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Arrays.asList(newAssignment));
        when(dataAggregationMapper.selectAssignmentNameById("ASSIGNMENT001"))
            .thenThrow(new RuntimeException("DB error"));
        when(dataAggregationMapper.selectStudentNewSubmissionsSince(anyString(), anyString(), any(LocalDateTime.class)))
            .thenReturn(Collections.emptyList());

        ArgumentCaptor<PerformanceChanges> captor = ArgumentCaptor.forClass(PerformanceChanges.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, atLeastOnce()).insert(captor.capture());
        
        boolean hasDefaultName = captor.getAllValues().stream()
            .anyMatch(change -> change.getAssignmentName() != null && 
                              change.getAssignmentName().contains("未知任务"));
        assertTrue(hasDefaultName);
    }

    @Test
    @DisplayName("无上周快照时跳过检测")
    void testDetectChanges_NoLastSnapshot() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(trackingServiceMapper.selectByStudentAndCourseAndDate(anyString(), anyString(), any(LocalDate.class)))
            .thenReturn(null);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(changesMapper, never()).insert(any(PerformanceChanges.class));
    }

    @Test
    @DisplayName("生成快照 - 验证快照数据完整性")
    void testGenerateSnapshot_DataCompleteness() {
        // Arrange
        when(studentPerformanceTrackingServiceMapper.selectAllActiveStudentIds()).thenReturn(Arrays.asList(studentId));
        when(dataAggregationMapper.selectCourseProgressByStudentId(studentId)).thenReturn(Arrays.asList(courseProgress));
        when(trackingServiceMapper.existsSnapshot(anyString(), anyString(), any(LocalDate.class))).thenReturn(false);
        when(dataAggregationMapper.selectCourseNameById(courseId)).thenReturn("Java编程");
        when(dataAggregationMapper.selectContributionRecords(anyString(), anyString())).thenReturn(Collections.emptyList());
        when(dataAggregationMapper.selectActiveAssignments(anyString(), anyString())).thenReturn(Collections.emptyList());

        ArgumentCaptor<StudentPerformanceSnapshots> captor = ArgumentCaptor.forClass(StudentPerformanceSnapshots.class);

        // Act
        trackingService.simplifiedWeeklyTracking();

        // Assert
        verify(trackingServiceMapper).insert(captor.capture());
        
        StudentPerformanceSnapshots snapshot = captor.getValue();
        assertNotNull(snapshot.getId());
        assertEquals(studentId, snapshot.getStudentId());
        assertEquals(courseId, snapshot.getCourseId());
        assertEquals("Java编程", snapshot.getCourseName());
        assertNotNull(snapshot.getSnapshotDate());
        assertEquals(BigDecimal.valueOf(85.0), snapshot.getCourseTotalScore());
        assertEquals(10, snapshot.getCourseRanking());
        assertEquals(8, snapshot.getCompletedTasks());
    }
}
